package com.sprite.framework.entity.util;

import java.util.concurrent.atomic.AtomicLong;

import com.sprite.framework.entity.Delegator;
import com.sprite.framework.entity.EntityCondition;
import com.sprite.framework.entity.EntityScriptExecutor;
import com.sprite.framework.entity.script.EntityView;
import com.sprite.framework.entity.transaction.TransactionExecutor;
import com.sprite.framework.entity.transaction.TransactionScript;
import com.sprite.utils.UtilCollection;

/**
 * 序列工具类
 * @author Jack
 *
 */
public final class SequenceUtil {
	private EntityScriptExecutor scriptExecutor;
	private Delegator delegator;
	
	private String sequenceName;
	private final AtomicLong sequenceValue = new AtomicLong(0);
	private final AtomicLong storedSequenceValue =new AtomicLong(0);     // 数据库中存贮值
	private final long bankSize;
	private final long beginValue;
	
	public SequenceUtil(String sequenceName, long beginValue, long bankSize, EntityScriptExecutor scriptExecutor, Delegator delegator){
		this.sequenceName = sequenceName;
		this.scriptExecutor = scriptExecutor;
		this.bankSize = bankSize;
		this.beginValue = beginValue;
		this.delegator = delegator;
	}

	private void store(){
		TransactionScript transactionScript = scriptExecutor.beginTransaction(true);
	
		transactionScript.execute(new TransactionExecutor() {
			
			@Override
			public void execute() {
				EntityView script = new EntityView("SequenceItem", "a");
				script.addViewField("a", "sequenceId");
				script.addViewField("a", "sequenceValue");
				script.setWhereCondition(EntityCondition.equal("sequenceId", sequenceName));
				SequenceItem item = UtilCollection.at(scriptExecutor.query(script, SequenceItem.class), 0);
				
				if(item == null){
					item = new SequenceItem();
					item.setSequenceId(sequenceName);
					sequenceValue.addAndGet(beginValue);
					storedSequenceValue.addAndGet(beginValue);
				}else {
					sequenceValue.set(item.getSequenceValue());
					storedSequenceValue.set(item.getSequenceValue());
					
					storedSequenceValue.addAndGet(bankSize);
					item.setSequenceValue(storedSequenceValue.get());
				}
				delegator.store("SequenceItem", item);
			}
		});
	}

	public long nextValue(){
		if(sequenceValue.get() >= storedSequenceValue.get()){
			synchronized (this) {
				if(sequenceValue.get() >= storedSequenceValue.get()){
					store();
				}
			}
		}

		return sequenceValue.addAndGet(1);
	}
	
	public static class SequenceItem{
		private String sequenceId;
		private long sequenceValue = 1000;
		
		public String getSequenceId() {
			return sequenceId;
		}
		public void setSequenceId(String sequenceId) {
			this.sequenceId = sequenceId;
		}
		public long getSequenceValue() {
			return sequenceValue;
		}
		public void setSequenceValue(long sequenceValue) {
			this.sequenceValue = sequenceValue;
		}
		
	}

}
